package tc.de.krawallmann.gravoblocks.game;

import java.util.Locale;

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.Sound;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.state.transition.FadeInTransition;
import org.newdawn.slick.state.transition.FadeOutTransition;

import tc.de.krawallmann.achievement.AchievementNotifier;
import tc.de.krawallmann.extension.AchievementExtension;
import tc.de.krawallmann.extension.SettingsExtension;
import tc.de.krawallmann.gravoblocks.achievements.Achievements;
import tc.de.krawallmann.gravoblocks.game.model.BlockColor;
import tc.de.krawallmann.gravoblocks.game.model.TetrisGrid;
import tc.de.krawallmann.gravoblocks.resource.Language;
import tc.de.krawallmann.gravoblocks.twl.widgets.GridView;
import tc.de.krawallmann.slick.game.AbstractExtendableGame;
import tc.de.krawallmann.slick.game.AbstractMMenuState;
import tc.de.krawallmann.twl.RootPane;
import de.matthiasmann.twl.Button;
import de.matthiasmann.twl.Label;

/**
 * The class MainMenuState displays the game's main menu.
 * @author KrawallMann
 * @version 1.0
 */
public class MainMenuState extends AbstractMMenuState {

	/** The Constant BUTTON60. */
	private static final String BUTTON60 = "button60"; //$NON-NLS-1$

	/** The exit. */
	private transient Button achievements;

	/** The click. */
	private transient Sound click;

	/** The exit. */
	private transient Button exit;

	/** The grid. */
	private transient final TetrisGrid grid;

	/** The grid2. */
	private transient final TetrisGrid grid2;

	/** The main grid view. */
	private transient GridView mainGridView;

	/** The notifier. */
	private transient final AchievementNotifier notifier = new AchievementNotifier();

	/** The play. */
	private transient Button play;

	/** The scores. */
	private transient Button scores;

	/** The sec grid view. */
	private transient GridView secGridView;

	/** The settings. */
	private transient Button settings;

	/** The version. */
	private transient Label version;

	private transient Button puzzle;

	/**
	 * Instantiates a new MainMenuState.
	 * 
	 * @param menuID
	 *            the menu's id
	 * @param game
	 *            the game
	 */
	public MainMenuState(final int menuID, final AbstractExtendableGame game) {
		super(menuID, game);
		grid = new TetrisGrid(6, 15);
		drawGravo();
		grid2 = new TetrisGrid(17, 7);
		drawBlocks();
	}

	/* (non-Javadoc)
	 * @see tc.de.krawallmann.slick.game.AbstractMMenuState#enter(org.newdawn.slick.GameContainer, org.newdawn.slick.state.StateBasedGame)
	 */
	@Override
	public void enter(final GameContainer container, final StateBasedGame game)
			throws SlickException {
		super.enter(container, game);
		((AbstractExtendableGame) game).getExtension(AchievementExtension.class)
				.addAchievementsListener(notifier);
	}

	/*
	 * (non-Javadoc)
	 * @see tc.de.krawallmann.slick.game.AbstractMMenuState#init(org.newdawn.
	 * slick.GameContainer, org.newdawn.slick.state.StateBasedGame)
	 */
	@Override
	public void init(final GameContainer container, final StateBasedGame game)
			throws SlickException {
		super.init(container, game);
		click = new Sound("tc/de/krawallmann/gravoblocks/resource/click.wav"); //$NON-NLS-1$
		setBackground(new Image("tc/de/krawallmann/gravoblocks/resource/mainmenu.jpg")); //$NON-NLS-1$
	}

	/*
	 * (non-Javadoc)
	 * @see tc.de.krawallmann.twlslick.BasicTWLGameState#layoutRootPane()
	 */
	@Override
	public void layoutRootPane() {
		super.layoutRootPane();

		// Adjust the sizes
		notifier.getAchievementLabel().adjustSize();
		mainGridView.adjustSize();
		secGridView.adjustSize();
		play.adjustSize();
		puzzle.adjustSize();
		scores.adjustSize();
		settings.adjustSize();
		exit.adjustSize();
		achievements.adjustSize();
		int maxwidth =
				Math.max(Math.max(play.getWidth(), scores.getWidth()),
						Math.max(settings.getWidth(), exit.getWidth()));
		maxwidth = Math.max(maxwidth, achievements.getWidth());
		play.setSize(maxwidth, play.getHeight());
		scores.setSize(maxwidth, scores.getHeight());
		settings.setSize(maxwidth, settings.getHeight());
		exit.setSize(maxwidth, exit.getHeight());
		achievements.setSize(maxwidth, play.getHeight());
		version.adjustSize();

		// Set the positions
		mainGridView.setPosition(50, 35);
		secGridView.setPosition(280, 0);
		play.setPosition(270, 200);
		puzzle.setPosition(570, 200);
		scores.setPosition(450, 300);
		settings.setPosition(320, 400);
		exit.setPosition(500, 500);
		achievements.setPosition(500 - maxwidth - 50, 500);
		notifier.layout(getContainer().getWidth());
		version.setPosition(0, getContainer().getHeight() - version.getHeight());
	}

	/* (non-Javadoc)
	 * @see tc.de.krawallmann.slick.game.AbstractMMenuState#leave(org.newdawn.slick.GameContainer, org.newdawn.slick.state.StateBasedGame)
	 */
	@Override
	public void leave(final GameContainer container, final StateBasedGame game)
			throws SlickException {
		((AbstractExtendableGame) game).getExtension(AchievementExtension.class)
				.removeAchievementsListener(notifier);
		super.leave(container, game);
	}

	/* (non-Javadoc)
	 * @see tc.de.krawallmann.slick.game.AbstractMMenuState#update(org.newdawn.slick.GameContainer, org.newdawn.slick.state.StateBasedGame, int)
	 */
	@Override
	public void update(final GameContainer container, final StateBasedGame game, final int delta)
			throws SlickException {
		super.update(container, game, delta);
		notifier.update(delta);
		if(!((AbstractExtendableGame) game).getExtension(AchievementExtension.class).isUnlocked(Achievements.GBWORKS)){
		((AbstractExtendableGame) game).getExtension(AchievementExtension.class).unlockAchievement(
				Achievements.GBWORKS);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see tc.de.krawallmann.twlslick.BasicTWLGameState#createRootPane()
	 */
	@Override
	protected RootPane createRootPane() {
		final RootPane pane = super.createRootPane();

		// Set root theme
		pane.setTheme(""); //$NON-NLS-1$

		// Create the widgets
		createWidgets();

		// Add callbacks
		addCallbacks();

		// Add the widgets
		addWidgets(pane);

		// Make the widgets focusable
		makeFocusable();
		return pane;
	}

	/**
	 * Adds the callbacks.
	 */
	protected void addCallbacks() {
		play.addCallback(new Runnable() {
			@Override
			public void run() {
				if (SettingsExtension.getSetting(
						GravoBlocksGame.USE_SOUND)) {
					click.play();
				}
				getGame().enterState(GravoBlocksGame.GAMEPLAYSTATE, new FadeOutTransition(),
						new FadeInTransition());
			}
		});

		scores.addCallback(new Runnable() {
			@Override
			public void run() {
				if (SettingsExtension.getSetting(
						GravoBlocksGame.USE_SOUND)) {
					click.play();
				}
				getGame().enterState(GravoBlocksGame.VIEWSCORESSTATE, new FadeOutTransition(),
						new FadeInTransition());
			}
		});
		
		puzzle.addCallback(new Runnable() {
			@Override
			public void run() {
				if (SettingsExtension.getSetting(
						GravoBlocksGame.USE_SOUND)) {
					click.play();
				}
				getGame().enterState(GravoBlocksGame.PUZZLEGAMESTATE, new FadeOutTransition(),
						new FadeInTransition());
			}
		});

		settings.addCallback(new Runnable() {
			@Override
			public void run() {
				if (SettingsExtension.getSetting(
						GravoBlocksGame.USE_SOUND)) {
					click.play();
				}
				getGame().enterState(GravoBlocksGame.SETTINGSSTATE, new FadeOutTransition(),
						new FadeInTransition());
			}
		});

		achievements.addCallback(new Runnable() {
			@Override
			public void run() {
				if (SettingsExtension.getSetting(
						GravoBlocksGame.USE_SOUND)) {
					click.play();
				}
				getGame().enterState(GravoBlocksGame.ACHIEVEMENTSSTATE, new FadeOutTransition(),
						new FadeInTransition());
			}
		});

		exit.addCallback(new Runnable() {
			@Override
			public void run() {
				if (SettingsExtension.getSetting(
						GravoBlocksGame.USE_SOUND)) {
					click.play();
				}
				getContainer().exit();
			}
		});
	}

	/**
	 * Make focusable.
	 */
	protected void makeFocusable() {
		makeFocusable(play);
		makeFocusable(puzzle);
		makeFocusable(scores);
		makeFocusable(settings);
		makeFocusable(achievements);
		makeFocusable(exit);
	}

	/**
	 * Adds the widgets.
	 * 
	 * @param pane
	 *            the pane
	 */
	protected void addWidgets(final RootPane pane) {
		pane.add(mainGridView);
		pane.add(secGridView);
		pane.add(play);
		pane.add(puzzle);
		pane.add(scores);
		pane.add(settings);
		pane.add(exit);
		pane.add(version);
		pane.add(achievements);
		pane.add(notifier.createAchievementLabel());
	}

	/**
	 * Creates the widgets.
	 */
	protected void createWidgets() {
		version = new Label(getGame().getVersion());
		version.setTheme("labelsmall"); //$NON-NLS-1$
		mainGridView = new GridView(grid);
		mainGridView.setTheme("gridview"); //$NON-NLS-1$
		mainGridView.init(false);

		secGridView = new GridView(grid2);
		secGridView.setTheme("gridviewtopopen"); //$NON-NLS-1$
		secGridView.init(false);

		play = new Button(Language.getString("MainMenuState.3")); //$NON-NLS-1$
		play.setTheme(MainMenuState.BUTTON60);
		play.setTooltipContent(Language.getString("MainMenuState.1")); //$NON-NLS-1$
		
		puzzle = new Button(Language.getString("MainMenuState.0")); //$NON-NLS-1$
		puzzle.setTheme(MainMenuState.BUTTON60);
		puzzle.setTooltipContent(Language.getString("MainMenuState.11")); //$NON-NLS-1$

		scores = new Button(Language.getString("MainMenuState.6")); //$NON-NLS-1$
		scores.setTooltipContent(Language.getString("MainMenuState.2")); //$NON-NLS-1$
		scores.setTheme(MainMenuState.BUTTON60);

		settings = new Button(Language.getString("MainMenuState.7")); //$NON-NLS-1$
		settings.setTooltipContent(Language.getString("MainMenuState.4")); //$NON-NLS-1$
		settings.setTheme(MainMenuState.BUTTON60);

		exit = new Button(Language.getString("MainMenuState.8")); //$NON-NLS-1$
		exit.setTooltipContent(Language.getString("MainMenuState.5")); //$NON-NLS-1$
		exit.setTheme(MainMenuState.BUTTON60);

		achievements = new Button(Language.getString("MainMenuState.9")); //$NON-NLS-1$
		achievements.setTooltipContent(Language.getString("MainMenuState.10")); //$NON-NLS-1
		if(Locale.getDefault().getLanguage().equalsIgnoreCase(Locale.GERMANY.getLanguage())){
			achievements.setTheme(MainMenuState.BUTTON60);
		}else{
			achievements.setTheme("button40"); //$NON-NLS-1$
		}
	}

	/**
	 * Draw blocks.
	 */
	private void drawBlocks() {
		// B
		fillBlock(grid2, 0, 2, BlockColor.ORANGE);
		fillBlock(grid2, 0, 3, BlockColor.ORANGE);
		fillBlock(grid2, 0, 4, BlockColor.ORANGE);
		fillBlock(grid2, 0, 5, BlockColor.ORANGE);
		fillBlock(grid2, 0, 6, BlockColor.ORANGE);
		fillBlock(grid2, 1, 4, BlockColor.ORANGE);
		fillBlock(grid2, 1, 2, BlockColor.ORANGE);
		fillBlock(grid2, 2, 3, BlockColor.ORANGE);
		fillBlock(grid2, 2, 5, BlockColor.ORANGE);
		fillBlock(grid2, 1, 6, BlockColor.ORANGE);

		// L
		fillBlock(grid2, 3, 2, BlockColor.GREEN);
		fillBlock(grid2, 3, 3, BlockColor.GREEN);
		fillBlock(grid2, 3, 4, BlockColor.GREEN);
		fillBlock(grid2, 3, 5, BlockColor.GREEN);
		fillBlock(grid2, 3, 6, BlockColor.GREEN);
		fillBlock(grid2, 4, 6, BlockColor.GREEN);
		fillBlock(grid2, 5, 6, BlockColor.GREEN);

		// O
		fillBlock(grid2, 5, 5, BlockColor.RED);
		fillBlock(grid2, 5, 4, BlockColor.RED);
		fillBlock(grid2, 5, 3, BlockColor.RED);
		fillBlock(grid2, 6, 2, BlockColor.RED);
		fillBlock(grid2, 6, 6, BlockColor.RED);
		fillBlock(grid2, 7, 5, BlockColor.RED);
		fillBlock(grid2, 7, 4, BlockColor.RED);
		fillBlock(grid2, 7, 3, BlockColor.RED);

		// C
		fillBlock(grid2, 8, 5, BlockColor.PURPLE);
		fillBlock(grid2, 8, 4, BlockColor.PURPLE);
		fillBlock(grid2, 8, 3, BlockColor.PURPLE);
		fillBlock(grid2, 9, 2, BlockColor.PURPLE);
		fillBlock(grid2, 9, 6, BlockColor.PURPLE);
		fillBlock(grid2, 10, 2, BlockColor.PURPLE);
		fillBlock(grid2, 10, 6, BlockColor.PURPLE);

		// K
		fillBlock(grid2, 11, 2, BlockColor.CYAN);
		fillBlock(grid2, 11, 3, BlockColor.CYAN);
		fillBlock(grid2, 11, 4, BlockColor.CYAN);
		fillBlock(grid2, 11, 5, BlockColor.CYAN);
		fillBlock(grid2, 11, 6, BlockColor.CYAN);
		fillBlock(grid2, 12, 4, BlockColor.CYAN);
		fillBlock(grid2, 13, 2, BlockColor.CYAN);
		fillBlock(grid2, 13, 3, BlockColor.CYAN);
		fillBlock(grid2, 13, 5, BlockColor.CYAN);
		fillBlock(grid2, 13, 6, BlockColor.CYAN);
		// S
		fillBlock(grid2, 15, 2, BlockColor.YELLOW);
		fillBlock(grid2, 16, 2, BlockColor.YELLOW);
		fillBlock(grid2, 15, 4, BlockColor.YELLOW);
		fillBlock(grid2, 14, 3, BlockColor.YELLOW);
		fillBlock(grid2, 16, 5, BlockColor.YELLOW);
		fillBlock(grid2, 15, 6, BlockColor.YELLOW);
		fillBlock(grid2, 14, 6, BlockColor.YELLOW);
	}

	/**
	 * Draw gravo.
	 */
	private void drawGravo() {
		// G
		fillBlock(grid, 2, 14, BlockColor.RED);
		fillBlock(grid, 3, 14, BlockColor.RED);
		fillBlock(grid, 4, 14, BlockColor.RED);
		fillBlock(grid, 4, 13, BlockColor.RED);
		fillBlock(grid, 4, 12, BlockColor.RED);
		fillBlock(grid, 3, 12, BlockColor.RED);
		fillBlock(grid, 1, 12, BlockColor.RED);
		fillBlock(grid, 1, 13, BlockColor.RED);

		// R
		fillBlock(grid, 1, 11, BlockColor.YELLOW);
		fillBlock(grid, 2, 11, BlockColor.YELLOW);
		fillBlock(grid, 3, 11, BlockColor.YELLOW);
		fillBlock(grid, 4, 11, BlockColor.YELLOW);
		fillBlock(grid, 1, 10, BlockColor.YELLOW);
		fillBlock(grid, 2, 9, BlockColor.YELLOW);
		fillBlock(grid, 3, 10, BlockColor.YELLOW);
		fillBlock(grid, 4, 9, BlockColor.YELLOW);

		// A
		fillBlock(grid, 4, 8, BlockColor.GREEN);
		fillBlock(grid, 3, 8, BlockColor.GREEN);
		fillBlock(grid, 2, 8, BlockColor.GREEN);
		fillBlock(grid, 1, 8, BlockColor.GREEN);
		fillBlock(grid, 1, 7, BlockColor.GREEN);
		fillBlock(grid, 3, 7, BlockColor.GREEN);
		fillBlock(grid, 4, 6, BlockColor.GREEN);
		fillBlock(grid, 3, 6, BlockColor.GREEN);
		fillBlock(grid, 2, 6, BlockColor.GREEN);
		fillBlock(grid, 1, 6, BlockColor.GREEN);

		// V
		fillBlock(grid, 3, 5, BlockColor.BLUE);
		fillBlock(grid, 2, 5, BlockColor.BLUE);
		fillBlock(grid, 1, 5, BlockColor.BLUE);
		fillBlock(grid, 3, 3, BlockColor.BLUE);
		fillBlock(grid, 2, 3, BlockColor.BLUE);
		fillBlock(grid, 1, 3, BlockColor.BLUE);
		fillBlock(grid, 4, 4, BlockColor.BLUE);

		// O
		fillBlock(grid, 4, 2, BlockColor.ORANGE);
		fillBlock(grid, 3, 2, BlockColor.ORANGE);
		fillBlock(grid, 2, 2, BlockColor.ORANGE);
		fillBlock(grid, 1, 2, BlockColor.ORANGE);

		fillBlock(grid, 4, 0, BlockColor.ORANGE);
		fillBlock(grid, 3, 0, BlockColor.ORANGE);
		fillBlock(grid, 2, 0, BlockColor.ORANGE);
		fillBlock(grid, 1, 0, BlockColor.ORANGE);
		fillBlock(grid, 4, 1, BlockColor.ORANGE);
		fillBlock(grid, 1, 1, BlockColor.ORANGE);
	}

	/**
	 * Fill block.
	 * 
	 * @param grid
	 *            the grid
	 * @param xPosition
	 *            the x position
	 * @param yPosition
	 *            the y position
	 * @param color
	 *            the color
	 */
	private void fillBlock(final TetrisGrid grid, final int xPosition, final int yPosition,
			final BlockColor color) {
		grid.getBlockAt(xPosition, yPosition).setBlocked(true);
		grid.getBlockAt(xPosition, yPosition).setColor(color);
	}
}
